﻿using Furion.CMS.Core;
using Furion.CMS.Core.EventSource;
using Furion.CMS.Core.Handlers;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.EventBus;
using Furion.TaskScheduler;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Furion.CMS.Domain
{
    public class OrganizationRoleFormatHandler<T> : AuditLogFormatHandler
        where T : struct
    {
        public override string GetRowKey(DbContext context, object entityValues, params string[] formatArgs)
        {
            if (entityValues is PropertyValues values)
            {
                var oid = values.GetValue<Guid>(nameof(OrganizationRole.OrganizationId));
                var rid = values.GetValue<int>(nameof(OrganizationRole.RoleId));
                var org = context.Find<OrganizationInfo>(oid);
                if (org == null) return "未知";
                var role = context.Find<RoleInfo>(rid);
                return $"{org.Name}角色-{role.Name}";
            }
            return "未知";
        }

        public override string[] GetChangeValue(DbContext context, object oldValue, object newValue)
        {
            if (typeof(T) == typeof(int))
            {
                int.TryParse(oldValue?.ToString(), out var oldRid);
                int.TryParse(newValue?.ToString(), out var newRid);
                var oldRole = context.Find<RoleInfo>(oldRid);
                var newRole = context.Find<RoleInfo>(newRid);

                return new string[2] { oldRole?.Name ?? "无", newRole?.Name ?? "无" };
            }
            else
            {
                Guid.TryParse(oldValue?.ToString(), out var oldOId);
                Guid.TryParse(newValue?.ToString(), out var newOId);
                var oldOrg = context.Find<OrganizationInfo>(oldOId);
                var newOrg = context.Find<OrganizationInfo>(newOId);

                return new string[2] { oldOrg?.Name ?? "无", newOrg?.Name ?? "无" };
            }
        }
    }

    /// <summary>
    /// 组织机构角色
    /// </summary>
    [OperateRecord("组织机构角色")]
    public class OrganizationRole : IEntity,
        IEntityTypeBuilder<OrganizationRole>,
        IEntityChangedListener<OrganizationRole>
    {
        /// <summary>
        /// 组织机构Id
        /// </summary>
        [OperateRecord("所属组织机构", true, typeof(OrganizationRoleFormatHandler<Guid>))]
        public Guid OrganizationId { get; set; }
        public virtual OrganizationInfo Organization { get; set; }
        /// <summary>
        /// 角色Id
        /// </summary>
        [OperateRecord("分配角色", typeof(OrganizationRoleFormatHandler<int>))]
        public int RoleId { get; set; }
        public virtual RoleInfo Role { get; set; }

        public void Configure(EntityTypeBuilder<OrganizationRole> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.UseDefaultTableNameDefine();

            entityBuilder.HasIndex(i => new { i.OrganizationId, i.RoleId });
        }

        public void OnChanged(OrganizationRole newEntity, OrganizationRole oldEntity, DbContext dbContext, Type dbContextLocator, EntityState state)
        {
            SpareTime.DoIt(() =>
            {
                Scoped.Create((_, scope) =>
                {
                    var services = scope.ServiceProvider;
                    // 获取数据库上下文
                    var dbContext = Db.GetDbContext(services);

                    var operationType = CacheOperationType.Add;
                    if (state == EntityState.Detached)
                    {// 移除
                        operationType = CacheOperationType.Remove;
                    }
                    // 触发事件
                    var eventPublisher = services.GetService<IEventPublisher>();
                    // 查询当前组织机构下的所属人员
                    newEntity.Organization = newEntity.Organization ?? dbContext.Find<OrganizationInfo>(newEntity.OrganizationId);
                    newEntity.Role = newEntity.Role ?? dbContext.Find<RoleInfo>(newEntity.RoleId);
                    // 加载机构的人员与权限信息集合
                    dbContext.Attach(newEntity.Organization).Collection(c => c.Users).Load();
                    dbContext.Attach(newEntity.Role).Collection(c => c.Permissions).Load();
                    // 获取角色的模块的依赖资源
                    var dependentResList = newEntity.Role.Permissions.Where(t => !string.IsNullOrWhiteSpace(t.DependentResources))
                        .SelectMany(s => s.DependentResources.Split(new String[] { "," }, StringSplitOptions.RemoveEmptyEntries));

                    // 缓存变更事件列表
                    var resourcePayload = newEntity.Organization.Users.Select(s => string.Format(CacheKeyConsts.PermissionResourceValue, newEntity.OrganizationId, s.Id));
                    var changeEvents = dependentResList.Select(s => new OnPermissionDataItemChange(operationType, string.Format(CacheKeyConsts.PermissionResource, s, ""), resourcePayload));
                    eventPublisher?.PublishAsync(new ChannelEventSource(EventIdConsts.PermissionDataItemManyChange, changeEvents));
                });
            });
        }
    }
}
